<template>
  <div style="display: flex; height: 100vh">
    <!-- 控制面板 -->
    <div
      style="
        width: 340px;
        background: #232323;
        color: #fff;
        padding: 20px;
        overflow-y: auto;
      "
    >
      <h2>相机控制实验室</h2>
      <el-form label-width="90px" style="margin-bottom: 14px">
        <el-form-item label="控制器类型">
          <el-select v-model="controlType" @change="switchControl">
            <el-option label="OrbitControls (轨道)" value="orbit" />
            <el-option label="TrackballControls (球体)" value="trackball" />
            <el-option label="MapControls (地图)" value="map" />
            <el-option label="FlyControls (飞行)" value="fly" />
          </el-select>
        </el-form-item>
        <el-form-item label="限制旋转">
          <el-switch v-model="limitRotate" @change="applyLimit" />
        </el-form-item>
        <el-form-item label="限制缩放">
          <el-switch v-model="limitZoom" @change="applyLimit" />
        </el-form-item>
        <el-form-item label="限制平移">
          <el-switch v-model="limitPan" @change="applyLimit" />
        </el-form-item>
        <el-form-item label="自动旋转">
          <el-switch v-model="autoRotate" @change="applyAutoRotate" />
        </el-form-item>
        <el-form-item>
          <el-button @click="resetView" type="primary">重置视角</el-button>
        </el-form-item>
        <el-form-item>
          <el-button @click="focusOnSphere" type="success"
            >聚焦球体（动画）</el-button
          >
        </el-form-item>
      </el-form>
      <div style="color: #eee; font-size: 14px; line-height: 1.7">
        <ul>
          <li>可动态切换不同控制器，体验不同交互方式。</li>
          <li>限制旋转/缩放/平移分别影响鼠标控制效果。</li>
          <li>“重置视角”将相机和控制器还原到初始。</li>
          <li>点击“聚焦球体”相机会平滑飞向目标。</li>
        </ul>
      </div>
    </div>
    <!-- three.js 区域 -->
    <div ref="threeBox" style="flex: 1; background: #222"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls";
import { MapControls } from "three/examples/jsm/controls/MapControls";
import { FlyControls } from "three/examples/jsm/controls/FlyControls";

// 控制器类型
const controlType = ref("orbit");
const autoRotate = ref(false);
const limitRotate = ref(false);
const limitZoom = ref(false);
const limitPan = ref(false);

const threeBox = ref(null);
let renderer, scene, camera;
let controls; // 当前控制器实例
let mesh, ground;
let animationFrameId;

// 记录初始参数用于重置
const initCamera = {
  position: new THREE.Vector3(3, 2, 7),
  target: new THREE.Vector3(0, 1, 0),
};

onMounted(() => {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x232323);

  camera = new THREE.PerspectiveCamera(
    60,
    threeBox.value.clientWidth / threeBox.value.clientHeight,
    0.1,
    100
  );
  camera.position.copy(initCamera.position);

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(threeBox.value.clientWidth, threeBox.value.clientHeight);
  threeBox.value.appendChild(renderer.domElement);

  // 地面
  ground = new THREE.Mesh(
    new THREE.PlaneGeometry(10, 10),
    new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.7 })
  );
  ground.rotation.x = -Math.PI / 2;
  ground.position.y = -1.2;
  ground.receiveShadow = true;
  scene.add(ground);

  // 球体
  mesh = new THREE.Mesh(
    new THREE.SphereGeometry(1, 48, 48),
    new THREE.MeshStandardMaterial({
      color: 0x3399ff,
      metalness: 0.4,
      roughness: 0.5,
    })
  );
  mesh.position.y = 1;
  mesh.castShadow = true;
  scene.add(mesh);

  // 灯光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
  scene.add(ambientLight);
  const dirLight = new THREE.DirectionalLight(0xffffff, 1.1);
  dirLight.position.set(4, 8, 4);
  dirLight.castShadow = true;
  scene.add(dirLight);

  scene.add(new THREE.AxesHelper(2));

  initControls();

  animate();
});

onBeforeUnmount(() => {
  cancelAnimationFrame(animationFrameId);
  renderer?.dispose?.();
  controls?.dispose?.();
});

// 初始化控制器
function initControls() {
  if (controls) controls.dispose();
  // 每次切换都重新绑定
  switch (controlType.value) {
    case "trackball":
      controls = new TrackballControls(camera, renderer.domElement);
      controls.noRotate = false;
      controls.noZoom = false;
      controls.noPan = false;
      break;
    case "map":
      controls = new MapControls(camera, renderer.domElement);
      controls.screenSpacePanning = true;
      break;
    case "fly":
      controls = new FlyControls(camera, renderer.domElement);
      controls.movementSpeed = 6;
      controls.rollSpeed = 0.5;
      controls.autoForward = false;
      controls.dragToLook = true;
      break;
    case "orbit":
    default:
      controls = new OrbitControls(camera, renderer.domElement);
      controls.enableDamping = true;
      break;
  }
  applyLimit();
  applyAutoRotate();
}

// 切换控制器
function switchControl() {
  nextTick(() => {
    initControls();
  });
}

// 限制功能应用
function applyLimit() {
  if (!controls) return;
  if (controlType.value === "orbit" || controlType.value === "map") {
    controls.enableRotate = !limitRotate.value;
    controls.enableZoom = !limitZoom.value;
    controls.enablePan = !limitPan.value;
  }
  if (controlType.value === "trackball") {
    controls.noRotate = !!limitRotate.value;
    controls.noZoom = !!limitZoom.value;
    controls.noPan = !!limitPan.value;
  }
  // FlyControls 没有这几个限制
}

// 自动旋转
function applyAutoRotate() {
  if (controls && controls.hasOwnProperty("autoRotate")) {
    controls.autoRotate = autoRotate.value;
  }
}

// 重置视角
function resetView() {
  camera.position.copy(initCamera.position);
  if (controls && controls.target) controls.target.copy(initCamera.target);
  if (controls && controls.reset) controls.reset();
}

// 动画聚焦球体
function focusOnSphere() {
  if (!controls) return;
  // 聚焦到球体中心 [0,1,0] 距离3.5的位置，缓动动画
  const target = new THREE.Vector3(0, 1, 0);
  const direction = new THREE.Vector3()
    .subVectors(camera.position, target)
    .normalize();
  const newPos = target.clone().add(direction.multiplyScalar(3.5));
  animateCameraMove(
    camera.position.clone(),
    newPos,
    controls.target?.clone?.() || new THREE.Vector3(),
    target,
    900
  );
}

// 相机动画函数（线性插值）
function animateCameraMove(
  fromPos,
  toPos,
  fromTarget,
  toTarget,
  duration = 800
) {
  let start = null;
  function step(ts) {
    if (!start) start = ts;
    const t = Math.min((ts - start) / duration, 1);
    camera.position.lerpVectors(fromPos, toPos, t);
    if (controls && controls.target)
      controls.target.lerpVectors(fromTarget, toTarget, t);
    if (t < 1) {
      requestAnimationFrame(step);
    }
  }
  requestAnimationFrame(step);
}

function animate() {
  animationFrameId = requestAnimationFrame(animate);
  mesh.rotation.y += 0.003;
  if (controls && controls.update) controls.update(1); // FlyControls 需要参数
  renderer.render(scene, camera);
}
</script>
